#include "Acceptor.h"
#include "Logger.h"
#include "InetAddress.h"

#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <unistd.h>

static int createNonblocking()
{
    // 创建一个非阻塞的 TCP 套接字
    int sockfd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP);
    if(sockfd < 0)
    {
        // 如果创建失败，打印错误信息
        LOG_FATAL("%s:%s:%d listen socket create err:%d\n", __FILE__, __FUNCTION__, __LINE__, errno);
    }
}

Acceptor::Acceptor(EventLoop *loop, const InetAddress &listenAddr, bool reuseport)
    : loop_(loop)
    , acceptSocket_(createNonblocking()) // 调用 createNonblocking() 创建一个非阻塞的套接字
    , acceptChannel_(loop, acceptSocket_.fd()) // 在 loop 上添加 acceptChannel_，用于监听套接字的读事件
    , listenning_(false)
{
    acceptSocket_.setReuseAddr(true); // 设置 SO_REUSEADDR，允许地址重用
    acceptSocket_.setReusePort(true); // 设置 SO_REUSEPORT，允许端口重用
    acceptSocket_.bindAddress(listenAddr); // 绑定地址和端口

    // 设置 acceptChannel_ 的回调函数为 handleRead，当有新的连接事件时会调用该函数
    acceptChannel_.setReadCallback(std::bind(&Acceptor::handleRead, this));
}

Acceptor::~Acceptor()
{
    acceptChannel_.disableAll(); // 关闭 acceptChannel_ 的所有事件
    acceptChannel_.remove(); // 在 loop_ 上删除 acceptChannel_
}

void Acceptor::listen()
{
    listenning_ = true; // 标记 acceptor 已经开始监听
    acceptSocket_.listen(); // 开始监听套接字
    acceptChannel_.enableReading(); // 在 loop_ 上启用 acceptChannel_ 的读事件
}

// 当有新的连接事件时会调用该函数
void Acceptor::handleRead()
{
    InetAddress peerAddr;
    int connfd = acceptSocket_.accept(&peerAddr); // 接收新连接，并返回新连接的文件描述符
    if(connfd > 0) // 如果接收成功
    {
        if(newConnectionCallback_) // 如果设置了新连接回调函数
        {
            newConnectionCallback_(connfd, peerAddr); // 调用新连接回调函数，并传递新连接的文件描述符和对端地址
        }
        else // 如果没有设置新连接回调函数
        {
            ::close(connfd); // 关闭新连接的文件描述符
        }
                
    }
    else // 如果接收失败
    {
        LOG_ERROR("%s:%s:%d accpet err:%d\n", __FILE__, __FUNCTION__, __LINE__, errno); // 打印错误信息
        if(errno == EMFILE) // 如果套接字数量已经达到系统限制
        {
            LOG_ERROR("%s:%s:%d sockfd reached limit! \n", __FILE__, __FUNCTION__, __LINE__); // 打印错误信息
        }
    }
}   
